이번에는 leaflet과 crosstalk을 활용하여 지도 시각화와 위젯 간 상호작용을 다뤄볼 것입니다. leaflet은 자바스크립트의 오픈소스 지도 라이브러리 Leaflet.js의 R 인터페이스입니다. crosstalk은 하나의 공유 데이터를 중심으로 여러 위젯들을 연결하며, linked brushing, filtering 등의 기능을 제공합니다. crosstalk은 데이터프레임을 입력으로 받는 HTML 위젯들에서 작동하며, 주요한 한계점들은 다음과 같습니다.
저작자가 직접 HTML 위젯을 적절히 수정해야 한다. crosstalk은 스스로 위젯들을 연동시켜주지는 않는다.
Crosstalk은 개별 데이터 포인트에 대해서만 작동하며, 데이터의 결합이나 요약을 표현하는 위젯들에는 작동하지 않는다. 예를 들어서 개별 데이터 포인트를 표현하는 산점도에는 적용될 수 있지만, 히스토그램에는 적용될 수 없다.
crosstalk은 큰 데이터에 적합하지 않다. 모든 데이터가 브라우저에 로드되어야 하기 때문이다.
Linked brushing은 하나의 플롯에서 발생한 하이라이트를 연결된 다른 플롯들에도 적용하는 기능입니다. 실습에 사용할 데이터는 2016년 서울시 총선 투표 결과 및 기타 동별 정보를 담고 있습니다.
library(tidyverse)
library(crosstalk)
library(plotly)
election = geojsonio::geojson_read("data/election.json", what = "sp")
elected = c("새누리당","더불어민주당","국민의당")[apply(election@data %>% select(새누리당, 더불어민주당, 국민의당), 1, which.max)]
election@data = election@data %>% mutate(당선 = elected)
colnames(election@data) = colnames(election@data) %>% str_replace(" ","")
crosstalk::SharedData로 데이터프레임을 감싸 여러 위젯들을 연결할 공유 데이터를 생성해줍니다. 이 객체를 이용해서 두 개의 그래프를 그렸습니다. 이후 subplot 함수로 두 개의 그래프를 묶어주고, highlight에 "plotly_selected"를 전달해주면 됩니다. 한 쪽 플롯에서 점들을 선택하면 다른 쪽 플롯에서도 하이라이트되는 것을 확인할 수 있습니다. crosstalk의 SharedData가 아닌 일반 데이터프레임으로 플롯을 그린다면 당연히 이 기능은 작동하지 않습니다.
# SharedData 생성
shared_elec = crosstalk::SharedData$new(election@data)
p1 = plot_ly(shared_elec, x = ~소득, y = ~노령화지수, legendgroup=~당선) %>%
add_markers(color=~당선, colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
p2 = plot_ly(shared_elec, x = ~장애등급별.장애인현황, y = ~보육시설, legendgroup=~당선) %>%
add_markers(color=~당선, colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
subplot(p1,p2) %>%
layout(xaxis = list(title = "소득"),
yaxis = list(title = "노령화지수"),
xaxis2 = list(title = "장애인현황"),
yaxis2 = list(title = "보육시설"),
height=400, width=850) %>%
highlight("plotly_selected")
크로스톡은 서로 다른 종류의 위젯들 간에도 잘 작동합니다. 다음은 지도와 산점도를 연결한 예제입니다.
library(leaflet)
library(geojsonio)
shared_elec = SharedData$new(election)
shared_elec_df = SharedData$new(election@data, group=shared_elec$groupName())
pal = colorFactor(c("#0D7440", "#2A88C5", "#C10D0D"), c("국민의당", "더불어민주당","새누리당"))
labs = lapply(seq(nrow(election@data)), function(i) {
paste0( '<p><b>', election@data[i, "읍면동명"], '</b></p><p>',
"<b>당선 : ", election@data[i, "당선"], '</b><p></p>',
"국민의당 : ", election@data[i, "국민의당"],'</p><p>',
"더불어민주당 : ", election@data[i, "더불어민주당"], '</p><p>',
"새누리당 : ", election@data[i, "새누리당"], '</p>')
})
leaflet(data = shared_elec) %>%
addProviderTiles("CartoDB.Positron") %>%
setView(126.982, 37.5502, zoom=10) %>%
addPolygons(
fillColor = ~pal(당선),
weight = 2,
opacity = 1,
color = "white",
fillOpacity = 0.5,
label = lapply(labs, htmltools::HTML),
highlightOptions = highlightOptions(
color = "#00ff00", opacity = 1, weight = 2, fillOpacity = 1,
bringToFront = TRUE, sendToBack = TRUE))
p1 = plot_ly(shared_elec_df, x = ~소득, y = ~노령화지수, legendgroup=~당선) %>%
add_markers(color=~당선, colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
p2 = plot_ly(shared_elec_df, x = ~장애등급별.장애인현황, y = ~보육시설, legendgroup=~당선) %>%
add_markers(color=~당선, colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
subplot(p1,p2) %>%
layout(xaxis = list(title = "소득"),
yaxis = list(title = "노령화지수"),
xaxis2 = list(title = "장애인현황"),
yaxis2 = list(title = "보육시설"),
height=400, width=850) %>%
highlight("plotly_selected")